package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"sync"
	"time"
)

type Proxy struct {
	HandraddrToconn map[string]*net.Conn `json:"raddrtoconn"`
	Handaddr        map[string]string    `json:"addrtoaddr"`
	HandladdrToconn map[string]*net.Conn `json:"laddrtoconn"`
}

var Defaultproxy = &Proxy{
	HandraddrToconn: make(map[string]*net.Conn, 5),
	Handaddr:        make(map[string]string, 5),
	HandladdrToconn: make(map[string]*net.Conn, 5)}

var (
	laddr  = flag.String("addr", "0.0.0.0:3200", "server:转发连接地址.")
	apiurl = flag.String("url", "/api", "api:设置api的url.")
	api    = flag.String("http.server", "127.0.0.1:8090", "api:监听地址.")
)

//#################################################方法#####################################
//HandraddrToconn of Defaultproxy注册方法
func (p *Proxy) MraddrToconn(addr string, rconn *net.Conn) {
	p.HandraddrToconn[addr] = rconn
}

//HandraddrToconn of Defaultproxy注销方法
func (p *Proxy) UnmaraddrToconn(addr string) {
	delete(p.HandraddrToconn, addr)
}

//HandraddrToconn of Defaultproxy注册方法
func (p *Proxy) MladdrToconn(addr string, lconn *net.Conn) {
	p.HandladdrToconn[addr] = lconn
}

//HandraddrToconn of Defaultproxy注销方法
func (p *Proxy) UnmaladdrToconn(addr string) {
	delete(p.HandladdrToconn, addr)
}

//Handaddr of Defaultproxy注册方法
func (p *Proxy) Maddr(laddr string, raddr string) {
	p.Handaddr[laddr] = raddr
}

//Handaddr of Defaultproxy注销方法
func (p *Proxy) Unmaddr(laddr string) {
	delete(p.Handaddr, laddr)
}

//************************************end*******************************************

func main() {
	flag.Parse()
	ln, err := net.Listen("tcp", *laddr)
	if err != nil {
		fmt.Println(err)
		return
	}
	go apifunc(*apiurl, *api)
	fmt.Println("server:程序准备就绪!!!")
	for {
		conn, err := ln.Accept()
		if err != nil {
			fmt.Println(err)
		}
		go process(&conn)
	}
}


//localtcpnet proces fuction.
func process(c *net.Conn) {
	//注册本地地址
	Defaultproxy.MladdrToconn((*c).RemoteAddr().String(), c)
	for {
		(*c).Write([]byte("处理状态正常!!\n"))
		time.Sleep(time.Minute* 1)
	}
}

//net.Conn readwrite function of  long conn
func longConnrw(lconn *net.Conn, rconn *net.Conn) {
	defer Defaultproxy.UnmaladdrToconn((*lconn).RemoteAddr().String())
	defer Defaultproxy.UnmaraddrToconn((*rconn).RemoteAddr().String())
	defer Defaultproxy.Unmaddr((*lconn).RemoteAddr().String())
	var wg sync.WaitGroup
	Defaultproxy.Maddr((*lconn).RemoteAddr().String(), (*rconn).RemoteAddr().String())
	lreader := bufio.NewReader(*lconn)
	rreader := bufio.NewReader(*rconn)
	lbuf := make([]byte, 1024*512)
	rbuf := make([]byte, 1024*512)
	wg.Add(2)
	go func() {
		defer wg.Done()
		for {
			n, err := lreader.Read(lbuf)
			if err == io.EOF && n == 0 {
				break
			}
			m, err := (*rconn).Write(lbuf[:n])
			if err != nil {
				fmt.Println("传出字节：", m, err)
			}
		}
	}()
	go func() {
		defer wg.Done()
		for {
			n, err := rreader.Read(rbuf)
			if err == io.EOF && n == 0 {
				break
			}
			m, err := (*lconn).Write(rbuf[:n])
			if err != nil {
				fmt.Println("传出字节：", m, err)
			}
		}
	}()
	wg.Wait()
}

//net.Conn readwrite function of  long conn
func shortConnrw(lconn *net.Conn, rconn *net.Conn) {
	defer Defaultproxy.UnmaladdrToconn((*lconn).RemoteAddr().String())
	defer Defaultproxy.UnmaraddrToconn((*rconn).RemoteAddr().String())
	defer Defaultproxy.Unmaddr((*lconn).RemoteAddr().String())
	var wg sync.WaitGroup
	Defaultproxy.Maddr((*lconn).RemoteAddr().String(), (*rconn).RemoteAddr().String())
	lreader := bufio.NewReader(*lconn)
	rreader := bufio.NewReader(*rconn)
	wg.Add(2)
	go func() {
		defer wg.Done()
		fromdata, err := lreader.ReadString('\n')
		if err != nil {
			fmt.Println(err)
			return
		}
		m, err := (*rconn).Write([]byte(fromdata))
		if err != nil {
			fmt.Println("传出字节：", m, err)
		}
	}()
	go func() {
		defer wg.Done()
		todata, err := rreader.ReadString('\n')
		if err != nil {
			fmt.Println(err)
			return
		}
		m, err := (*lconn).Write([]byte(todata))
		if err != nil {
			fmt.Println("传出字节：", m, err)
		}
	}()
	wg.Wait()
}

//dial function of net tcp.
func dialfunc(addr string) *net.Conn {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		fmt.Println(err)
	}
	Defaultproxy.MraddrToconn(conn.RemoteAddr().String(), &conn)
	return &conn
}

/**
   ++++++++api+++++++
**/
//api for defaultproxy
type Apiserver struct {
	Api      bool   `json:"isapi"`
	Conntype string `json:"conntype"`
	Toaddr   string `json:"target"`
	Laddr    string `json:"local"`
}

var Defaultapi = &Apiserver{
	Api:      false,
	Conntype: "short",
}

func apifunc(apiurl string, apiaddr string) {
	http.HandleFunc(apiurl, f1)
	err := http.ListenAndServe(apiaddr, nil)
	if err != nil {
		fmt.Println("api server is over!", err)
		return
	}
}

//api hander func
func f1(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		apidata, err := json.Marshal(Defaultapi)
		if err != nil {
			fmt.Println("defaulapi 解析失败!", err)
			return
		}
		getdata, err := json.Marshal(Defaultproxy)
		if err != nil {
			fmt.Println("defaultproxy 解析失败!", err)
			return
		}
		w.Write(apidata)
		w.Write([]byte("\n"))
		w.Write(getdata)
	case "POST":
		postdata, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Println(err)
		}
		err = json.Unmarshal(postdata, &Defaultapi)
		if err != nil {
			fmt.Println("post 反序列化失败：", err)
			return
		}
		w.Write(postdata)
		switch Defaultapi.Conntype {
		case "long":
			go longConnrw(Defaultproxy.HandladdrToconn[Defaultapi.Laddr], dialfunc(Defaultapi.Toaddr))
		case "short":
			go longConnrw(Defaultproxy.HandladdrToconn[Defaultapi.Laddr], dialfunc(Defaultapi.Toaddr))
		default:
			w.Write([]byte("请输入正确的conntype字段，例如：long或short."))
		}
	default:
		fmt.Println("非法请求：", r.URL.Host+":"+r.URL.Port())
		w.Write([]byte(http.StatusText(404)))
	}
}